/**
 * 增强音效管理器 - Phase 4 音效完善
 * 支持背景音乐、环境音效、交互音效、祭祀音效
 */

interface AudioSource {
  buffer?: AudioBuffer;
  source?: AudioBufferSourceNode;
  gainNode?: GainNode;
  isPlaying: boolean;
  volume: number;
  loop: boolean;
  type: 'ambient' | 'bgm' | 'effect';
}

class AudioManager {
  private ambientVolume: number = 0.4;
  private audioContext: AudioContext | null = null;
  private backgroundMusicVolume: number = 0.3;
  private currentBackgroundMusic: null | string = null;
  private effectVolume: number = 0.8;
  private enabled: boolean = true;
  private masterVolume: number = 0.7;
  private sounds: Map<string, AudioSource> = new Map();

  constructor() {
    // 尝试在用户交互后初始化AudioContext
    document.addEventListener('click', this.initAudioContext, { once: true });
    document.addEventListener('keydown', this.initAudioContext, { once: true });
  }

  /**
   * 淡入淡出背景音乐
   */
  public fadeBGM(musicName: string, duration: number = 2000) {
    if (!this.enabled) return;

    const currentSource = this.sounds.get(this.currentBackgroundMusic || '');
    const newSource = this.sounds.get(musicName);

    if (!newSource || newSource.type !== 'bgm') return;

    // 淡出当前音乐
    if (currentSource && currentSource.gainNode) {
      this.fadeOut(currentSource.gainNode, duration);
    }

    // 淡入新音乐
    setTimeout(() => {
      this.playBGM(musicName);
      if (newSource.gainNode) {
        this.fadeIn(newSource.gainNode, duration);
      }
    }, duration / 2);
  }

  /**
   * 获取当前播放状态
   */
  public getPlaybackStatus() {
    return {
      enabled: this.enabled,
      masterVolume: this.masterVolume,
      bgmVolume: this.backgroundMusicVolume,
      effectVolume: this.effectVolume,
      ambientVolume: this.ambientVolume,
      currentBGM: this.currentBackgroundMusic,
      playingSounds: [...this.sounds.entries()]
        .filter(([_, source]) => source.isPlaying)
        .map(([name, _]) => name),
    };
  }

  /**
   * 获取音效列表
   */
  public getSoundList() {
    return {
      // 交互音效
      effects: {
        bell: '钟声',
        drum: '鼓声',
        incense: '上香音效',
        prayer: '诵经',
        'wooden-fish': '木鱼',
        'ancient-bell': '古钟',
        guzheng: '古筝',
        sutra: '经文',
        chanting: '念白',
        'temple-bell': '寺钟',
        'ritual-gong': '法锣',
      },
      // 背景音乐
      bgm: {
        'guzheng-bg': '古筝背景',
        'guqin-bg': '古琴背景',
        'temple-bg': '寺庙背景',
      },
      // 环境音效
      ambient: {
        wind: '风声',
        rain: '雨声',
        birds: '鸟鸣',
        cricket: '虫鸣',
      },
    };
  }

  /**
   * 初始化所有音效
   */
  public async init() {
    this.initAudioContext();

    // 基础交互音效
    await this.loadSound('bell', 'effect', 0.8, false);
    await this.loadSound('incense', 'effect', 0.6, false);
    await this.loadSound('drum', 'effect', 0.7, false);
    await this.loadSound('prayer', 'effect', 0.5, false);

    // 增强交互音效
    await this.loadSound('wooden-fish', 'effect', 0.6, false);
    await this.loadSound('ancient-bell', 'effect', 0.7, false);
    await this.loadSound('guzheng', 'effect', 0.4, false);

    // 背景音乐（古筝、古琴）
    await this.loadSound('guzheng-bg', 'bgm', 0.3, true);
    await this.loadSound('guqin-bg', 'bgm', 0.3, true);
    await this.loadSound('temple-bg', 'bgm', 0.25, true);

    // 环境音效
    await this.loadSound('wind', 'ambient', 0.4, true);
    await this.loadSound('rain', 'ambient', 0.5, true);
    await this.loadSound('birds', 'ambient', 0.3, true);
    await this.loadSound('cricket', 'ambient', 0.2, true);

    // 祭祀音效
    await this.loadSound('sutra', 'effect', 0.6, false);
    await this.loadSound('chanting', 'effect', 0.5, false);
    await this.loadSound('temple-bell', 'effect', 0.7, false);
    await this.loadSound('ritual-gong', 'effect', 0.8, false);

    console.log('🎵 Enhanced Audio System Ready - All sounds loaded');
  }

  /**
   * 播放音效（使用程序生成音频）
   */
  public play(soundName: string, loop: boolean = false) {
    if (!this.enabled || !this.audioContext) {
      this.initAudioContext();
      if (!this.audioContext) return;
    }

    const audioSource = this.sounds.get(soundName);
    if (!audioSource) {
      console.warn(`Sound "${soundName}" not found`);
      return;
    }

    // 停止当前播放
    if (audioSource.isPlaying && audioSource.source) {
      try {
        audioSource.source.stop();
      } catch {
        // 忽略错误
      }
    }

    console.log(`🔊 Playing sound: ${soundName} (${audioSource.type})`);

    // 使用程序生成音效
    this.playSynthSound(soundName, audioSource);

    audioSource.isPlaying = true;
    setTimeout(() => {
      audioSource.isPlaying = false;
    }, this.getSoundDuration(soundName));
  }

  /**
   * 播放环境音效（生成白噪声）
   */
  public playAmbient(ambientName: string) {
    if (!this.enabled || !this.audioContext) {
      this.initAudioContext();
      if (!this.audioContext) return;
    }

    const audioSource = this.sounds.get(ambientName);
    if (!audioSource || audioSource.type !== 'ambient') {
      console.warn(`Ambient sound "${ambientName}" not found`);
      return;
    }

    console.log(`🌿 Playing ambient sound: ${ambientName}`);

    // 播放环境白噪声
    this.playAmbientNoise(ambientName, audioSource);
    audioSource.isPlaying = true;
  }

  /**
   * 播放背景音乐（生成和弦音效）
   */
  public playBGM(musicName: string) {
    if (!this.enabled || !this.audioContext) {
      this.initAudioContext();
      if (!this.audioContext) return;
    }

    // 停止当前背景音乐
    this.stopBGM();

    const audioSource = this.sounds.get(musicName);
    if (!audioSource || audioSource.type !== 'bgm') {
      console.warn(`Background music "${musicName}" not found`);
      return;
    }

    this.currentBackgroundMusic = musicName;
    console.log(`🎵 Playing background music: ${musicName}`);

    // 播放循环和弦音效作为背景音乐
    this.playAmbientChords(musicName, audioSource);
    audioSource.isPlaying = true;
  }

  /**
   * 播放祭祀音效
   */
  public playRitual(effectName: string) {
    console.log(`🙏 Playing ritual sound: ${effectName}`);
    this.play(effectName);
  }

  /**
   * 设置环境音效音量
   */
  public setAmbientVolume(volume: number) {
    this.ambientVolume = Math.max(0, Math.min(1, volume));
    this.updateAmbientVolumes();
    console.log(
      `🌿 Ambient volume set to: ${Math.round(this.ambientVolume * 100)}%`,
    );
  }

  /**
   * 设置背景音乐音量
   */
  public setBGMVolume(volume: number) {
    this.backgroundMusicVolume = Math.max(0, Math.min(1, volume));
    this.updateBGMVolumes();
    console.log(
      `🎵 BGM volume set to: ${Math.round(this.backgroundMusicVolume * 100)}%`,
    );
  }

  /**
   * 设置音效音量
   */
  public setEffectVolume(volume: number) {
    this.effectVolume = Math.max(0, Math.min(1, volume));
    console.log(
      `🔊 Effect volume set to: ${Math.round(this.effectVolume * 100)}%`,
    );
  }

  /**
   * 启用/禁用音效
   */
  public setEnabled(enabled: boolean) {
    this.enabled = enabled;
    if (!enabled) {
      this.stopBGM();
      this.stopAllAmbient();
    }
    console.log(`🔊 Audio ${enabled ? 'enabled' : 'disabled'}`);
  }

  /**
   * 设置主音量
   */
  public setMasterVolume(volume: number) {
    this.masterVolume = Math.max(0, Math.min(1, volume));
    this.updateAllVolumes();
    console.log(
      `🔊 Master volume set to: ${Math.round(this.masterVolume * 100)}%`,
    );
  }

  /**
   * 停止所有环境音效
   */
  public stopAllAmbient() {
    this.sounds.forEach((audioSource, name) => {
      if (audioSource.type === 'ambient' && audioSource.isPlaying) {
        if (audioSource.source) {
          try {
            audioSource.source.stop();
          } catch {
            // 忽略错误
          }
        }
        audioSource.isPlaying = false;
        console.log(`🌿 Stopped ambient sound: ${name}`);
      }
    });
  }

  /**
   * 停止环境音效
   */
  public stopAmbient(ambientName: string) {
    const audioSource = this.sounds.get(ambientName);
    if (audioSource && audioSource.isPlaying) {
      if (audioSource.source) {
        try {
          audioSource.source.stop();
        } catch {
          // 忽略错误
        }
      }
      audioSource.isPlaying = false;
      console.log(`🌿 Stopped ambient sound: ${ambientName}`);
    }
  }

  /**
   * 停止背景音乐
   */
  public stopBGM() {
    if (this.currentBackgroundMusic) {
      const audioSource = this.sounds.get(this.currentBackgroundMusic);
      if (audioSource) {
        if (audioSource.source) {
          try {
            audioSource.source.stop();
          } catch {
            // 忽略错误
          }
        }
        audioSource.isPlaying = false;
        console.log(
          `⏹️ Stopped background music: ${this.currentBackgroundMusic}`,
        );
      }
      this.currentBackgroundMusic = null;
    }
  }

  /**
   * 淡入效果
   */
  private fadeIn(gainNode: GainNode, duration: number) {
    const startTime = this.audioContext!.currentTime;
    gainNode.gain.setValueAtTime(0, startTime);
    gainNode.gain.linearRampToValueAtTime(
      this.getAdjustedVolume(gainNode.gain.value, 'bgm'),
      startTime + duration / 1000,
    );
  }

  /**
   * 淡出效果
   */
  private fadeOut(gainNode: GainNode, duration: number) {
    const startTime = this.audioContext!.currentTime;
    gainNode.gain.linearRampToValueAtTime(0, startTime + duration / 1000);
  }

  /**
   * 获取调整后的音量
   */
  private getAdjustedVolume(
    volume: number,
    type: 'ambient' | 'bgm' | 'effect',
  ): number {
    let typeMultiplier = 1;
    switch (type) {
      case 'ambient': {
        typeMultiplier = this.ambientVolume;
        break;
      }
      case 'bgm': {
        typeMultiplier = this.backgroundMusicVolume;
        break;
      }
      case 'effect': {
        typeMultiplier = this.effectVolume;
        break;
      }
    }
    return volume * typeMultiplier * this.masterVolume;
  }

  /**
   * 获取音效时长
   */
  private getSoundDuration(soundName: string): number {
    const durations: Record<string, number> = {
      bell: 2000,
      'ancient-bell': 2000,
      'temple-bell': 2000,
      drum: 300,
      incense: 1000,
      'wooden-fish': 150,
      prayer: 2000,
      sutra: 2000,
      chanting: 2000,
    };
    return durations[soundName] || 500;
  }

  private initAudioContext = () => {
    if (!this.audioContext) {
      this.audioContext = new (window.AudioContext ||
        (window as any).webkitAudioContext)();
      console.log('🎵 AudioContext initialized');
    }
  };

  /**
   * 加载音效
   */
  private async loadSound(
    name: string,
    type: 'ambient' | 'bgm' | 'effect',
    volume: number,
    loop: boolean = false,
  ) {
    if (!this.audioContext) {
      console.warn('AudioContext not initialized');
      return;
    }

    // 创建音效源对象
    const audioSource: AudioSource = {
      isPlaying: false,
      volume,
      loop,
      type,
    };

    // 创建增益节点
    if (this.audioContext) {
      audioSource.gainNode = this.audioContext.createGain();
      audioSource.gainNode.connect(this.audioContext.destination);
      audioSource.gainNode.gain.value = this.getAdjustedVolume(volume, type);
    }

    this.sounds.set(name, audioSource);
    console.log(`🎵 Loaded sound: ${name} (${type})`);
  }

  /**
   * 播放和弦背景音乐
   */
  private playAmbientChords(musicName: string, audioSource: AudioSource) {
    if (!this.audioContext || !audioSource.gainNode) return;

    const ctx = this.audioContext;
    const frequencies = musicName.includes('guzheng')
      ? [261.63, 329.63, 392] // C大调和弦（古筝）
      : [220, 277.18, 329.63]; // A小调和弦（古琴）

    frequencies.forEach((freq, index) => {
      const oscillator = ctx.createOscillator();
      const envelope = ctx.createGain();

      oscillator.type = 'sine';
      oscillator.frequency.value = freq;

      envelope.gain.setValueAtTime(0, ctx.currentTime);
      envelope.gain.linearRampToValueAtTime(0.03, ctx.currentTime + 1);
      envelope.gain.linearRampToValueAtTime(0.02, ctx.currentTime + 4);

      oscillator.connect(envelope);
      envelope.connect(audioSource.gainNode);

      oscillator.start(ctx.currentTime);

      // 循环播放
      if (audioSource.source) {
        try {
          audioSource.source.stop();
        } catch {
          // 忽略
        }
      }
      audioSource.source = oscillator;
    });
  }

  /**
   * 播放环境白噪声
   */
  private playAmbientNoise(ambientName: string, audioSource: AudioSource) {
    if (!this.audioContext || !audioSource.gainNode) return;

    const ctx = this.audioContext;
    const bufferSize = ctx.sampleRate * 2;
    const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
    const data = buffer.getChannelData(0);

    // 根据不同环境音生成不同的白噪声
    const intensity =
      ambientName === 'rain' ? 0.5 : ambientName === 'wind' ? 0.3 : 0.2;
    for (let i = 0; i < bufferSize; i++) {
      data[i] = (Math.random() * 2 - 1) * intensity;
    }

    const source = ctx.createBufferSource();
    source.buffer = buffer;
    source.loop = true;

    source.connect(audioSource.gainNode);
    source.start(ctx.currentTime);

    if (audioSource.source) {
      try {
        audioSource.source.stop();
      } catch {
        // 忽略
      }
    }
    audioSource.source = source;
  }

  /**
   * 钟声音效
   */
  private playBellSound(
    ctx: AudioContext,
    gainNode: GainNode,
    startTime: number,
  ) {
    const oscillator = ctx.createOscillator();
    const envelope = ctx.createGain();

    oscillator.type = 'sine';
    oscillator.frequency.setValueAtTime(400, startTime);
    oscillator.frequency.exponentialRampToValueAtTime(200, startTime + 1);

    envelope.gain.setValueAtTime(0.3, startTime);
    envelope.gain.exponentialRampToValueAtTime(0.01, startTime + 2);

    oscillator.connect(envelope);
    envelope.connect(gainNode);

    oscillator.start(startTime);
    oscillator.stop(startTime + 2);
  }

  /**
   * 默认音效
   */
  private playDefaultSound(
    ctx: AudioContext,
    gainNode: GainNode,
    startTime: number,
  ) {
    const oscillator = ctx.createOscillator();
    const envelope = ctx.createGain();

    oscillator.frequency.setValueAtTime(440, startTime);
    envelope.gain.setValueAtTime(0.2, startTime);
    envelope.gain.exponentialRampToValueAtTime(0.01, startTime + 0.5);

    oscillator.connect(envelope);
    envelope.connect(gainNode);

    oscillator.start(startTime);
    oscillator.stop(startTime + 0.5);
  }

  /**
   * 鼓声音效
   */
  private playDrumSound(
    ctx: AudioContext,
    gainNode: GainNode,
    startTime: number,
  ) {
    const oscillator = ctx.createOscillator();
    const envelope = ctx.createGain();

    oscillator.type = 'triangle';
    oscillator.frequency.setValueAtTime(100, startTime);
    oscillator.frequency.exponentialRampToValueAtTime(50, startTime + 0.1);

    envelope.gain.setValueAtTime(0.5, startTime);
    envelope.gain.exponentialRampToValueAtTime(0.01, startTime + 0.3);

    oscillator.connect(envelope);
    envelope.connect(gainNode);

    oscillator.start(startTime);
    oscillator.stop(startTime + 0.3);
  }

  /**
   * 上香音效（轻柔）
   */
  private playIncenseSound(
    ctx: AudioContext,
    gainNode: GainNode,
    startTime: number,
  ) {
    const oscillator = ctx.createOscillator();
    const envelope = ctx.createGain();

    oscillator.type = 'sine';
    oscillator.frequency.setValueAtTime(800, startTime);
    oscillator.frequency.linearRampToValueAtTime(1200, startTime + 0.5);

    envelope.gain.setValueAtTime(0.1, startTime);
    envelope.gain.linearRampToValueAtTime(0.2, startTime + 0.2);
    envelope.gain.exponentialRampToValueAtTime(0.01, startTime + 1);

    oscillator.connect(envelope);
    envelope.connect(gainNode);

    oscillator.start(startTime);
    oscillator.stop(startTime + 1);
  }

  /**
   * 诵经音效（低沉）
   */
  private playPrayerSound(
    ctx: AudioContext,
    gainNode: GainNode,
    startTime: number,
  ) {
    const oscillator = ctx.createOscillator();
    const envelope = ctx.createGain();

    oscillator.type = 'sawtooth';
    oscillator.frequency.setValueAtTime(150, startTime);
    oscillator.frequency.linearRampToValueAtTime(180, startTime + 1);

    envelope.gain.setValueAtTime(0.15, startTime);
    envelope.gain.linearRampToValueAtTime(0.2, startTime + 0.5);
    envelope.gain.exponentialRampToValueAtTime(0.01, startTime + 2);

    oscillator.connect(envelope);
    envelope.connect(gainNode);

    oscillator.start(startTime);
    oscillator.stop(startTime + 2);
  }

  /**
   * 使用合成器播放音效
   */
  private playSynthSound(soundName: string, audioSource: AudioSource) {
    if (!this.audioContext || !audioSource.gainNode) return;

    const ctx = this.audioContext;
    const now = ctx.currentTime;

    switch (soundName) {
      case 'ancient-bell':
      case 'bell':
      case 'temple-bell': {
        this.playBellSound(ctx, audioSource.gainNode, now);
        break;
      }
      case 'chanting':
      case 'prayer':
      case 'sutra': {
        this.playPrayerSound(ctx, audioSource.gainNode, now);
        break;
      }
      case 'drum': {
        this.playDrumSound(ctx, audioSource.gainNode, now);
        break;
      }
      case 'incense': {
        this.playIncenseSound(ctx, audioSource.gainNode, now);
        break;
      }
      case 'wooden-fish': {
        this.playWoodenFishSound(ctx, audioSource.gainNode, now);
        break;
      }
      default: {
        this.playDefaultSound(ctx, audioSource.gainNode, now);
      }
    }
  }

  /**
   * 木鱼音效
   */
  private playWoodenFishSound(
    ctx: AudioContext,
    gainNode: GainNode,
    startTime: number,
  ) {
    const oscillator = ctx.createOscillator();
    const envelope = ctx.createGain();

    oscillator.type = 'square';
    oscillator.frequency.setValueAtTime(600, startTime);

    envelope.gain.setValueAtTime(0.2, startTime);
    envelope.gain.exponentialRampToValueAtTime(0.01, startTime + 0.15);

    oscillator.connect(envelope);
    envelope.connect(gainNode);

    oscillator.start(startTime);
    oscillator.stop(startTime + 0.15);
  }

  /**
   * 更新所有音量
   */
  private updateAllVolumes() {
    this.sounds.forEach((audioSource) => {
      if (audioSource.gainNode) {
        audioSource.gainNode.gain.value = this.getAdjustedVolume(
          audioSource.volume,
          audioSource.type,
        );
      }
    });
  }

  /**
   * 更新环境音效音量
   */
  private updateAmbientVolumes() {
    this.sounds.forEach((audioSource) => {
      if (audioSource.type === 'ambient' && audioSource.gainNode) {
        audioSource.gainNode.gain.value = this.getAdjustedVolume(
          audioSource.volume,
          'ambient',
        );
      }
    });
  }

  /**
   * 更新背景音乐音量
   */
  private updateBGMVolumes() {
    this.sounds.forEach((audioSource) => {
      if (audioSource.type === 'bgm' && audioSource.gainNode) {
        audioSource.gainNode.gain.value = this.getAdjustedVolume(
          audioSource.volume,
          'bgm',
        );
      }
    });
  }
}

export const audioManager = new AudioManager();
